const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'reject'; // 失败

/*
    Promise接收一个函数作为执行器并立即执行
*/
class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject) // 成功调用resolve，失败调用reject
        }
        catch(e) { // 捕获错误
            this.reject(e)
        }
        
    }

    status = PENDING; // 默认状态为“等待”
    value = undefined;
    reason = undefined;
    successCallback = [] // 成功后回调
    failCallback = [] // 失败后回调

    resolve = value => {
        if(this.status !== PENDING) { // 如果状态不为等待则直接返回
            return
        }
        this.status = FULFILLED // 状态改为成功
        this.value = value // 保存成功后的值
        // this.successCallback && this.successCallback(this.value)

        while(this.successCallback.length) { // 成功后回调
            let fn = this.successCallback.shift()
            fn && fn()
        }
    }

    reject = reason => {
        if(this.status !== PENDING) { // 如果状态不为等待则直接返回
            return
        }
        this.status = REJECTED // 状态改为失败
        this.reason = reason // 保存失败原因

        while(this.failCallback.length) {
            let fn = this.failCallback.shift()
            fn && fn()
        }
    }

    then(successCallback, failCallback) { // 返回一个Promise实例，实现链式调用
        // 如果没有参数，补一个函数，传递值
        successCallback = successCallback? successCallback: value => value
        failCallback = failCallback? failCallback: reason => {throw reason}

        // 建立新的Promise对象并返回
        let promiseNew = new MyPromise((resolve, reject) => {
            if(this.status === FULFILLED) { // 成功状态调用成功回调
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value) // 传递返回值
                        resolvePromise(promiseNew, x, resolve, reject)    
                    }
                    catch(e) { // 错误捕获
                        reject(e)
                    }
                }, 0)
            }
            else if(this.status === REJECTED) { // 失败状态调用失败回调
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason) // 传递返回值
                        resolvePromise(promiseNew, x, resolve, reject)    
                    }
                    catch(e) { // 错误捕获
                        reject(e)
                    }
                }, 0)
            }
            else { // 等待状态时缓存回调，延后执行
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value) // 传递返回值
                            resolvePromise(promiseNew, x, resolve, reject)    
                        }
                        catch(e) { // 错误捕获
                            reject(e)
                        }
                    }, 0)
                }) 
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.value) // 传递返回值
                            resolvePromise(promiseNew, x, resolve, reject)    
                        }
                        catch(e) { // 错误捕获
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        return promiseNew
    }

    finally(callback) {
        return this.then(value => { // 在成功状态下执行回调
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => { // // 在失败状态下执行回调
            return MyPromise.resolve(callback()).then(() => {
                throw reason
            })
        })
    }

    catch(failCallback) {
        return this.then(undefined, failCallback) // 只传入失败回调
    }

    static all(array) {
        let result = []
        let index = 0 // 已添加数据计数

        // console.log('array', array)

        return new MyPromise((resolve, reject) => {
            function addData(key, value) { // 向结果追加数据
                result[key] = value
                index++
                if(index === array.length) { // 当所有数据都处理完毕后调用resolve
                    resolve(result)
                }
            }

            for(let i = 0; i < array.length; i++) { // 循环处理数组中的数据
                let current = array[i]
                if(current instanceof MyPromise) { // Promise对象
                    current.then(value => addData(i, value), reason => reject(reason))
                }
                else { // 普通值
                    addData(i, array[i])
                }
            }
            
        })
    }

    static resolve(value) {
        // 如果是Promise对象则直接返回，如果是普通对象包裹成Promise对象返回
        return value instanceof MyPromise? value: new MyPromise(resolve => resolve(value))
    }
}

/*
    解析Promise返回值，循环调用检测
*/
function resolvePromise(promiseNew, v, resolve, reject) {
    if(promiseNew === v) { // 如果成功回调的返回值和Promise对象相等则抛出错误并返回
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }

    if(v instanceof MyPromise) { // 传递的是Promise对象
        v.then(resolve, reject)
    }
    else { // 传递的是普通值或对象
        resolve(v)
    }
}

module.exports = MyPromise;